# include "LecteurFonction.h"


LecteurFonction::LecteurFonction(LecteurSymbole *lectSymb, vector <LecteurPhraseAbstrait *>&vf)
    : LecteurPhraseAbstrait()
{
    ls = lectSymb;
    // La fonction a accès aux fonctions déclarées avant :
    for (unsigned j=0; j<vf.size(); j++)
        ajFonction(vf[j]);
    arbre = programme();
}


// <fonction> ::= fonction ( [<variable>] {,<variable>}) <seqInst> [retour <expression>;] finfonc;
Noeud* LecteurFonction::programme(){
    sauterSymCour("fonction");
    testerSymCour("<VARIABLE>");

    nom = ls->getSymCour().getChaine();
    ls->suivant();
    sauterSymCour("(");
    if (ls->getSymCour() != ")")
        do{
            if (ls->getSymCour()==",")
                ls->suivant();
            testerSymCour("<VARIABLE>");
            parametres.push_back(ts.chercheAjoute(ls->getSymCour()));
            ls->suivant();
        } while (ls->getSymCour()==",");
    sauterSymCour(")");
    NoeudSeqInst* si = (NoeudSeqInst*)seqInst();
    if (ls->getSymCour()=="retour")
        si->ajouteInstruction(instRetour());
    else
        si->ajouteInstruction(new NoeudRetour(new SymboleValue(Symbole("0"))));
    sauterSymCour("finfonc");
    return si;
}

void LecteurFonction::genCode(fstream &f){
    // nom de la fonction
    f << "int " << nom << "(";
    // paramètres
    for (unsigned i=0; i<getNbParam(); i++){
        SymboleValue* s;
        s = (SymboleValue*) parametres[i];
        f << "int " << s->getChaine() ;
        if (i<getNbParam()-1)
            f << ", ";
    }
    f << ")\n{\n";
    // code des variables
    for (unsigned i=0; i<ts.size(); i++){
        if (ts[i]=="<VARIABLE>"){
            // ne pas redeclarer les parametres de la fonc
            unsigned ind;
            for (ind=0; ind<parametres.size(); ind++)
            {
                if ( ((void*)parametres[ind]) == ((void*)&ts[i]) )
                    break;
            }
            // si la variable n'est pas un parametre
            if (ind == parametres.size()){
                f << "    int ";
                ts[i].genCode(f, 0);
                f << ";\n";
            }
        }
    }
    // code de la fonction
    arbre->genCode(f, 1);
    f << "}\n\n";
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurFonction::instRetour(){
    sauterSymCour("retour");
    Noeud * retour = new NoeudRetour(expression());
    sauterSymCour(";");
    return retour;
}

int LecteurFonction::getValeur(vector<int> & p){
    for (unsigned int i = 0; i < getNbParam(); i++){
        parametres[i]->setValeur(p[i]);
    }
    return arbre->getValeur();
}